﻿using System;

namespace Pfz.Threading.Disposers
{
	/// <summary>
	/// Class returned by UpgradeableLock method.
	/// </summary>
	public struct YieldUpgradeableLock:
		IDisposable
	{
		private YieldReaderWriterLock _lock;
		private bool _upgraded;

		internal YieldUpgradeableLock(YieldReaderWriterLock yieldLock)
		{
			_lock = yieldLock;
			_upgraded = false;
		}

		/// <summary>
		/// Upgrades this lock to a write-lock.
		/// </summary>
		public YieldWriteLock DisposableUpgrade()
		{
			var yieldLock = _lock;
			if (yieldLock == null)
				throw new ObjectDisposedException(GetType().FullName);

			yieldLock._lock.UpgradeToWriteLock();
			return new YieldWriteLock(yieldLock);
		}

		/// <summary>
		/// Upgrades the lock to a write-lock.
		/// </summary>
		public void Upgrade()
		{
			var yieldLock = _lock;
			if (yieldLock == null)
				throw new ObjectDisposedException(GetType().FullName);

			if (_upgraded)
				return;

			_upgraded = true;
			yieldLock._lock.UpgradeToWriteLock();
		}

		/// <summary>
		/// Releases the lock.
		/// </summary>
		public void Dispose()
		{
			var yieldLock = _lock;

			if (yieldLock != null)
			{
				_lock = null;

				if (_upgraded)
					yieldLock._lock.ExitUpgradedLock();
				else
					yieldLock._lock.ExitUpgradeableLock();
			}
		}
	}
}
